/**
 * 变量的类型
 * @param {String} oData
 */
export const typeOf = (oData: any) => {
  return Object.prototype.toString
    .apply(oData)
    .match(/\[object (.*?)\]/)[1]
    .toLowerCase()
}

/**
 * 设置数量显示位，不足指定位用前面用零填充
 *
 * @param {Number} nValue 数值
 * @param {Number|undefined} nSize 显示的数位(2)
 * @return {String}
 */
export const fix = (nValue, nSize = 2) => {
  let nOffset = nSize - String(nValue).length
  if (nOffset < 0) {
    nOffset = 0
  }

  return '0'.repeat(nOffset) + nValue
}

/**
 * 将字符串时间转换成时间对象
 *
 * @param {String|Date|Number} sDateTime
 *  字符串类型参数，支持格式如下：
 *  UTC 标准时间
 *
 *  yyyy-MM-dd hh:mm:ss
 *
 *  yyyy-MM-dd
 *
 *  MM-dd hh:mm
 *
 *  hh:mm:ss
 *
 *  MM-dd
 *
 *  hh:mm
 *
 * @return {Date}
 */
export const parseDate = (sDateTime: any) => {
  var dDate = null
  var sDateType = typeOf(sDateTime)

  // 检测参数类型
  if (sDateType === 'date') {
    // 日期对象型
    dDate = sDateTime
  } else if (sDateType === 'number') {
    // 毫秒值类型
    dDate = new Date(Number(sDateTime))
  } else if (sDateType === 'string') {
    // 字数串类型
    sDateTime = sDateTime.replace(/-/g, '/')
    // 首先使用标准日期格式来实例化
    dDate = new Date(sDateTime)

    /*
     * 如果是无效的日期，则再进一步分析，否则可直接使用
     * 或者是非 yy-MM-dd 的三段日期，两段的也不行
     */
    if (
      dDate.toString() === 'Invalid Date' ||
      sDateTime.split('/').length < 3
    ) {
      var asDate = []
      var asTime = []

      // 分割日期与时间
      var asDateTime = sDateTime.split(' ')
      var sSplitedDate = asDateTime[0]

      // 检测分割结果段数
      if (asDateTime.length === 2) {
        // 有两段，则参数包括日期和时间

        asDate = sSplitedDate.split('/')
        asTime = sDateTime[1].split(':')
      } else {
        // 不是两段，当作只有日期或时间来处理

        // 检测分割后的日期里，是否有(-)符号，如果有则表示这段是日期的，否则为时间的
        if (sSplitedDate.indexOf('/') > -1) {
          // 日期型

          asDate = sSplitedDate.split('/')
        } else {
          // 时间型

          asTime = sSplitedDate.split(':')
        }
      }

      var nNow = new Date()

      // 日期段没传则使用当天
      var nYear = nNow.getFullYear()
      var nMonth = nNow.getMonth()
      var nDay = nNow.getDate()

      // 时间段没传则使用零点
      var nHours = 0
      var nMinutes = 0
      var nSeconds = 0

      // 检测分割后的日期段，是否有值
      if (asDate.length) {
        if (asDate.length === 3) {
          // 三段式日期

          nYear = asDate[0] >> 0
          nMonth = asDate[1] >> 0
          nDay = asDate[2] >> 0
        } else {
          // 两段式日期

          nMonth = asDate[0] >> 0
          nDay = asDate[1] >> 0
        }

        // 如果参数传的年是两位数，则换算成四位整年
        if (nYear < 1900) {
          nYear += 1900
        }

        // 月份要减一
        nMonth--
      }

      // 检测分割后的时间段，是否有值
      if (asTime.length) {
        nHours = asTime[0] >> 0
        nMinutes = asTime[1] >> 0

        // 三段式的值，表示包括毫秒
        if (asTime.length === 3) {
          nSeconds = asTime[2] >> 0
        }
      }

      // 实例段日期对象
      dDate = new Date(nYear, nMonth, nDay, nHours, nMinutes, nSeconds)
    }
  }

  return dDate
}
/**
 * 格式化日期时间
 * 如 yyyy-MM-dd、yyyy-MM-dd hh:mm:ss W
 *
 * @param {String|Date|Number} dDate 要格式化的日期对象
 * @param {String} sTemplate 要模式化的模板
 *  y 年
 *  M 月
 *  d 日
 *  h 时
 *  m 分
 *  s 秒
 *  S 毫秒
 *  q 季
 *  w 第多少周
 *  W 星期几
 * @return {String}
 */
export const formatDate = (dDate, sTemplate = 'yyyy-MM-dd hh:mm:ss') => {
  // 先解析一下日期参数
  dDate = parseDate(dDate)

  // 检测解析有效性
  if (!dDate) {
    return ''
  }

  var nFullYear = dDate.getFullYear() // 四位整年
  var nYear = nFullYear.toString().substring(2) // 两位年
  var nMonth = dDate.getMonth() + 1 // 月份
  var nDay = dDate.getDate() // 日

  var nHours = dDate.getHours() // 时
  var nMinutes = dDate.getMinutes() // 分
  var nSeconds = dDate.getSeconds() // 秒

  var nMilliseconds = dDate.getMilliseconds() // 毫秒
  var nQuarter = Math.floor((nMonth + 3) / 3) // 季
  var nWeek = _iso8601Week(dDate) // 周
  var nWeekDay = getWeekDay(dDate) // 星期几

  var oFullFlags = {
    yyyy: nFullYear, // 年
    MM: fix(nMonth), // 月
    dd: fix(nDay), // 日
    hh: fix(nHours), // 时
    mm: fix(nMinutes), // 分
    ss: fix(nSeconds), // 秒
    S: nMilliseconds, // 毫秒
    q: nQuarter, // 季
    w: nWeek,
    W: nWeekDay, // 星期几
  }

  var oFlags = {
    yy: nYear, // 年
    M: nMonth, // 月
    d: nDay, // 日
    h: nHours, // 时
    m: nMinutes, // 分
    s: nSeconds, // 秒
  }

  // 逐一替换各属性
  var sDate = sTemplate
  var p

  // 先替换多位的
  for (p in oFullFlags) {
    sDate = sDate.replace(p, oFullFlags[p])
  }

  // 再替换单位的
  for (p in oFlags) {
    sDate = sDate.replace(p, oFlags[p])
  }

  return sDate

  /**
   * 计算当前日期为当年的第几周
   *
   * @param {Date} date
   * @return {Number}
   */
  function _iso8601Week(date) {
    var time
    var checkDate = new Date(date.getTime())

    // Find Thursday of this week starting on Monday
    checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7))

    time = checkDate.getTime()
    checkDate.setMonth(0) // Compare with Jan 1
    checkDate.setDate(1)
    return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1
  }

  /**
   * 计算当前日期为当年的第几周
   *
   * @param {Date} date
   * @return {Number}
   */
  function getWeekDay(date) {
    var time = new Date(date.getTime())

    var day = time.getDay()
    var str = '星期'
    switch (day) {
      case 0:
        str += '日'
        break
      case 1:
        str += '一'
        break
      case 2:
        str += '二'
        break
      case 3:
        str += '三'
        break
      case 4:
        str += '四'
        break
      case 5:
        str += '五'
        break
      case 6:
        str += '六'
        break
    }
    return str
  }
}
